package com.xydtech.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 打包文件为zip
 *
 * @author yjs
 * @date 2023/2/20 16:38
 */
public class UrlFilesToZip {
    private static final Logger logger = LoggerFactory.getLogger(UrlFilesToZip.class);

    public final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();

    //通过url下载zip
    public static void filesdown(HttpServletResponse response, List<String> urls, String name) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ZipOutputStream zos = new ZipOutputStream(bos);
            int idx = 1;
            for (String oneFile : urls) {
                byte[] bytes = getFileFromURL(oneFile);
                //可以自动检测byte[]中文件格式，就是有点慢，如果要求速度就顶死
                //String fileTypeByStream = getFileTypeByStream(bytes);
                zos.putNextEntry(new ZipEntry(name + idx + ".doc"));
                zos.write(bytes, 0, bytes.length);
                zos.closeEntry();
                idx++;
            }
            zos.close();
            OutputStream os = response.getOutputStream();
            os.write(bos.toByteArray());
            os.close();
        } catch (FileNotFoundException ex) {
            logger.error("FileNotFoundException", ex);
        } catch (Exception ex) {
            logger.error("Exception", ex);
        }
    }


    //根据文件链接把文件下载下来并且转成字节码
    public static byte[] getFileFromURL(String urlPath) {
        byte[] data = null;
        InputStream is = null;
        HttpURLConnection conn = null;
        try {
            URL url = new URL(urlPath);
            conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            // conn.setDoOutput(true);
//            conn.setRequestMethod("GET");
            conn.setConnectTimeout(6000);
            is = conn.getInputStream();
            if (conn.getResponseCode() == 200) {
                data = readInputStream(is);
            } else {
                data = null;
            }
        } catch (MalformedURLException e) {
            logger.error("MalformedURLException", e);
        } catch (IOException e) {
            logger.error("IOException", e);
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                logger.error("IOException", e);
            }
            conn.disconnect();
        }
        return data;
    }


    private static byte[] readInputStream(InputStream is) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length = -1;
        try {
            while ((length = is.read(buffer)) != -1) {
                baos.write(buffer, 0, length);
            }
            baos.flush();
        } catch (IOException e) {
            logger.error("IOException", e);
        }
        byte[] data = baos.toByteArray();
        try {
            is.close();
            baos.close();
        } catch (IOException e) {
            logger.error("IOException", e);
        }
        return data;
    }

    private static void getAllFileType() {
        FILE_TYPE_MAP.put("jpg", "FFD8FF"); //JPEG (jpg)
        FILE_TYPE_MAP.put("png", "89504E47");  //PNG (png)
        FILE_TYPE_MAP.put("gif", "47494638");  //GIF (gif)
        FILE_TYPE_MAP.put("tif", "49492A00");  //TIFF (tif)
        FILE_TYPE_MAP.put("bmp", "424D"); //Windows Bitmap (bmp)
        FILE_TYPE_MAP.put("dwg", "41433130"); //CAD (dwg)
        FILE_TYPE_MAP.put("html", "68746D6C3E");  //HTML (html)
        FILE_TYPE_MAP.put("rtf", "7B5C727466");  //Rich Text Format (rtf)
        FILE_TYPE_MAP.put("xml", "3C3F786D6C");
        FILE_TYPE_MAP.put("zip", "504B0304");
        FILE_TYPE_MAP.put("rar", "52617221");
        FILE_TYPE_MAP.put("psd", "38425053");  //Photoshop (psd)
        FILE_TYPE_MAP.put("eml", "44656C69766572792D646174653A");  //Email [thorough only] (eml)
        FILE_TYPE_MAP.put("dbx", "CFAD12FEC5FD746F");  //Outlook Express (dbx)
        FILE_TYPE_MAP.put("pst", "2142444E");  //Outlook (pst)
        FILE_TYPE_MAP.put("xls", "D0CF11E0");  //MS Word
        FILE_TYPE_MAP.put("docx", "504B0304"); //doxc
        FILE_TYPE_MAP.put("doc", "D0CF11E0");  //MS Excel 注意：word 和 excel的文件头一样
        FILE_TYPE_MAP.put("mdb", "5374616E64617264204A");  //MS Access (mdb)
        FILE_TYPE_MAP.put("wpd", "FF575043"); //WordPerfect (wpd)
        FILE_TYPE_MAP.put("eps", "252150532D41646F6265");
        FILE_TYPE_MAP.put("ps", "252150532D41646F6265");
        FILE_TYPE_MAP.put("pdf", "255044462D312E");  //Adobe Acrobat (pdf)
        FILE_TYPE_MAP.put("qdf", "AC9EBD8F");  //Quicken (qdf)
        FILE_TYPE_MAP.put("pwl", "E3828596");  //Windows Password (pwl)
        FILE_TYPE_MAP.put("wav", "57415645");  //Wave (wav)
        FILE_TYPE_MAP.put("avi", "41564920");
        FILE_TYPE_MAP.put("ram", "2E7261FD");  //Real Audio (ram)
        FILE_TYPE_MAP.put("rm", "2E524D46");  //Real Media (rm)
        FILE_TYPE_MAP.put("mpg", "000001BA");  //
        FILE_TYPE_MAP.put("mov", "6D6F6F76");  //Quicktime (mov)
        FILE_TYPE_MAP.put("asf", "3026B2758E66CF11"); //Windows Media (asf)
        FILE_TYPE_MAP.put("mid", "4D546864");  //MIDI (mid)
    }


    public final static String getFileTypeByStream(byte[] b) {
        String filetypeHex = String.valueOf(getFileHexString(b));
        Iterator<Map.Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();
        while (entryiterator.hasNext()) {
            Map.Entry<String, String> entry = entryiterator.next();
            String fileTypeHexValue = entry.getValue();
            if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {
                return entry.getKey();
            }
        }
        return null;
    }


    public final static String getFileHexString(byte[] b) {
        StringBuilder stringBuilder = new StringBuilder();
        if (b == null || b.length <= 0) {
            return null;
        }
        for (int i = 0; i < b.length; i++) {
            int v = b[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }
    /**
     * 压缩文件
     * @param datumName 压缩包名称
     * @param filePathList 附件路径
     * @param fileZip  压缩包存储地址
     * @return File
     * @throws Exception Exception
     */
    public static File compressedFileToZip(String datumName, List<String> filePathList,String fileZip) throws Exception {
        //压缩包具体名称（拼接时间戳防止重名）
        String zipFileName = datumName + "-" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".zip";
        //生成压缩包存储地址（最后会删掉）
        fileZip = fileZip+ zipFileName;
        OutputStream os=null;
        ZipOutputStream zos = null ;
        File file = new File(fileZip);
        try {
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            os=new FileOutputStream(file);
            //压缩文件
            zos = new ZipOutputStream(os);
            byte[] buf = new byte[1024];
            for (String filePath : filePathList) {
                File tempFile = new File(filePath);
                //在压缩包中添加文件夹
                //zos.putNextEntry(new ZipEntry("测试/"+tempFile.getName()));
                //直接在压缩包中添加文件
                zos.putNextEntry(new ZipEntry(tempFile.getName()));
                int len;
                FileInputStream in = new FileInputStream(tempFile);
                while ((len = in.read(buf)) != -1){
                    zos.write(buf, 0, len);
                }
                zos.closeEntry();
                in.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.info(e.toString());
            throw new Exception("文件打包:"+e.getMessage());
        }finally {
            //关闭流
            if(zos != null){
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //关闭流
            if(os!= null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return file;
    }
    /**
     * 输出文件流到response
     *
     * @param response response
     * @param fileName fileName
     * @throws IOException IOException
     */
    public static void writeFileToRes(HttpServletResponse response, String fileName, File file) throws IOException {
        FileInputStream inputStream = new FileInputStream(file);
        //1.设置文件ContentType类型，这样设置，会自动判断下载文件类型
        //response.setContentType("application/octet-stream");
        //2.设置文件头：最后一个参数是设置下载文件名
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        response.addHeader("Content-Length", "" + file.length());

        //3.通过response获取ServletOutputStream对象(out)
        ServletOutputStream out = response.getOutputStream();

        int b = 0;
        byte[] buffer = new byte[1024];
        while (b != -1) {
            b = inputStream.read(buffer);
            //4.写到输出流(out)中
            out.write(buffer, 0, b);
        }
        out.flush();
        out.close();
        inputStream.close();
    }
}
